/*
 * Copyright 2023, Haiku, Inc.
 * Distributed under the terms of the MIT License.
 */

#include "CpuStateLoongArch64.h"

#include <new>

#include <string.h>

#include "Register.h"


CpuStateLoongArch64::CpuStateLoongArch64()
	:
	fSetRegisters()
{
	memset(fIntRegisters, 0, sizeof(fIntRegisters));
	memset(fFpRegisters, 0, sizeof(fFpRegisters));
}


CpuStateLoongArch64::CpuStateLoongArch64(const loongarch64_debug_cpu_state& state)
	:
	fSetRegisters()
{
	// 设置通用寄存器
	SetIntRegister(LOONGARCH64_REGISTER_R0, 0); // 零寄存器始终为0
	SetIntRegister(LOONGARCH64_REGISTER_RA, state.ra);
	SetIntRegister(LOONGARCH64_REGISTER_TP, state.tp);
	SetIntRegister(LOONGARCH64_REGISTER_SP, state.sp);
	SetIntRegister(LOONGARCH64_REGISTER_A0, state.a0);
	SetIntRegister(LOONGARCH64_REGISTER_A1, state.a1);
	SetIntRegister(LOONGARCH64_REGISTER_A2, state.a2);
	SetIntRegister(LOONGARCH64_REGISTER_A3, state.a3);
	SetIntRegister(LOONGARCH64_REGISTER_A4, state.a4);
	SetIntRegister(LOONGARCH64_REGISTER_A5, state.a5);
	SetIntRegister(LOONGARCH64_REGISTER_A6, state.a6);
	SetIntRegister(LOONGARCH64_REGISTER_A7, state.a7);
	SetIntRegister(LOONGARCH64_REGISTER_T0, state.t0);
	SetIntRegister(LOONGARCH64_REGISTER_T1, state.t1);
	SetIntRegister(LOONGARCH64_REGISTER_T2, state.t2);
	SetIntRegister(LOONGARCH64_REGISTER_T3, state.t3);
	SetIntRegister(LOONGARCH64_REGISTER_T4, state.t4);
	SetIntRegister(LOONGARCH64_REGISTER_T5, state.t5);
	SetIntRegister(LOONGARCH64_REGISTER_T6, state.t6);
	SetIntRegister(LOONGARCH64_REGISTER_T7, state.t7);
	SetIntRegister(LOONGARCH64_REGISTER_T8, state.t8);
	SetIntRegister(LOONGARCH64_REGISTER_S0, state.s0);
	SetIntRegister(LOONGARCH64_REGISTER_S1, state.s1);
	SetIntRegister(LOONGARCH64_REGISTER_S2, state.s2);
	SetIntRegister(LOONGARCH64_REGISTER_S3, state.s3);
	SetIntRegister(LOONGARCH64_REGISTER_S4, state.s4);
	SetIntRegister(LOONGARCH64_REGISTER_S5, state.s5);
	SetIntRegister(LOONGARCH64_REGISTER_S6, state.s6);
	SetIntRegister(LOONGARCH64_REGISTER_S7, state.s7);
	SetIntRegister(LOONGARCH64_REGISTER_S8, state.s8);
	SetIntRegister(LOONGARCH64_REGISTER_PC, state.pc);

	// 设置浮点寄存器
	SetFpRegister(LOONGARCH64_REGISTER_F0 - LOONGARCH64_INT_REGISTER_END, state.f0);
	SetFpRegister(LOONGARCH64_REGISTER_F1 - LOONGARCH64_INT_REGISTER_END, state.f1);
	SetFpRegister(LOONGARCH64_REGISTER_F2 - LOONGARCH64_INT_REGISTER_END, state.f2);
	SetFpRegister(LOONGARCH64_REGISTER_F3 - LOONGARCH64_INT_REGISTER_END, state.f3);
	SetFpRegister(LOONGARCH64_REGISTER_F4 - LOONGARCH64_INT_REGISTER_END, state.f4);
	SetFpRegister(LOONGARCH64_REGISTER_F5 - LOONGARCH64_INT_REGISTER_END, state.f5);
	SetFpRegister(LOONGARCH64_REGISTER_F6 - LOONGARCH64_INT_REGISTER_END, state.f6);
	SetFpRegister(LOONGARCH64_REGISTER_F7 - LOONGARCH64_INT_REGISTER_END, state.f7);
	SetFpRegister(LOONGARCH64_REGISTER_F8 - LOONGARCH64_INT_REGISTER_END, state.f8);
	SetFpRegister(LOONGARCH64_REGISTER_F9 - LOONGARCH64_INT_REGISTER_END, state.f9);
	SetFpRegister(LOONGARCH64_REGISTER_F10 - LOONGARCH64_INT_REGISTER_END, state.f10);
	SetFpRegister(LOONGARCH64_REGISTER_F11 - LOONGARCH64_INT_REGISTER_END, state.f11);
	SetFpRegister(LOONGARCH64_REGISTER_F12 - LOONGARCH64_INT_REGISTER_END, state.f12);
	SetFpRegister(LOONGARCH64_REGISTER_F13 - LOONGARCH64_INT_REGISTER_END, state.f13);
	SetFpRegister(LOONGARCH64_REGISTER_F14 - LOONGARCH64_INT_REGISTER_END, state.f14);
	SetFpRegister(LOONGARCH64_REGISTER_F15 - LOONGARCH64_INT_REGISTER_END, state.f15);
	SetFpRegister(LOONGARCH64_REGISTER_F16 - LOONGARCH64_INT_REGISTER_END, state.f16);
	SetFpRegister(LOONGARCH64_REGISTER_F17 - LOONGARCH64_INT_REGISTER_END, state.f17);
	SetFpRegister(LOONGARCH64_REGISTER_F18 - LOONGARCH64_INT_REGISTER_END, state.f18);
	SetFpRegister(LOONGARCH64_REGISTER_F19 - LOONGARCH64_INT_REGISTER_END, state.f19);
	SetFpRegister(LOONGARCH64_REGISTER_F20 - LOONGARCH64_INT_REGISTER_END, state.f20);
	SetFpRegister(LOONGARCH64_REGISTER_F21 - LOONGARCH64_INT_REGISTER_END, state.f21);
	SetFpRegister(LOONGARCH64_REGISTER_F22 - LOONGARCH64_INT_REGISTER_END, state.f22);
	SetFpRegister(LOONGARCH64_REGISTER_F23 - LOONGARCH64_INT_REGISTER_END, state.f23);
	SetFpRegister(LOONGARCH64_REGISTER_F24 - LOONGARCH64_INT_REGISTER_END, state.f24);
	SetFpRegister(LOONGARCH64_REGISTER_F25 - LOONGARCH64_INT_REGISTER_END, state.f25);
	SetFpRegister(LOONGARCH64_REGISTER_F26 - LOONGARCH64_INT_REGISTER_END, state.f26);
	SetFpRegister(LOONGARCH64_REGISTER_F27 - LOONGARCH64_INT_REGISTER_END, state.f27);
	SetFpRegister(LOONGARCH64_REGISTER_F28 - LOONGARCH64_INT_REGISTER_END, state.f28);
	SetFpRegister(LOONGARCH64_REGISTER_F29 - LOONGARCH64_INT_REGISTER_END, state.f29);
	SetFpRegister(LOONGARCH64_REGISTER_F30 - LOONGARCH64_INT_REGISTER_END, state.f30);
	SetFpRegister(LOONGARCH64_REGISTER_F31 - LOONGARCH64_INT_REGISTER_END, state.f31);
}


CpuStateLoongArch64::~CpuStateLoongArch64()
{
}


status_t
CpuStateLoongArch64::Clone(CpuState*& _clone) const
{
	CpuStateLoongArch64* clone = new(std::nothrow) CpuStateLoongArch64;
	if (clone == NULL)
		return B_NO_MEMORY;

	memcpy(clone->fIntRegisters, fIntRegisters, sizeof(fIntRegisters));
	memcpy(clone->fFpRegisters, fFpRegisters, sizeof(fFpRegisters));
	clone->fSetRegisters = fSetRegisters;

	_clone = clone;
	return B_OK;
}


status_t
CpuStateLoongArch64::UpdateDebugState(void* state, size_t size) const
{
	if (size != sizeof(loongarch64_debug_cpu_state))
		return B_BAD_VALUE;

	loongarch64_debug_cpu_state& debugState
		= *(loongarch64_debug_cpu_state*)state;

	// 更新通用寄存器
	debugState.ra = IntRegisterValue(LOONGARCH64_REGISTER_RA);
	debugState.tp = IntRegisterValue(LOONGARCH64_REGISTER_TP);
	debugState.sp = IntRegisterValue(LOONGARCH64_REGISTER_SP);
	debugState.a0 = IntRegisterValue(LOONGARCH64_REGISTER_A0);
	debugState.a1 = IntRegisterValue(LOONGARCH64_REGISTER_A1);
	debugState.a2 = IntRegisterValue(LOONGARCH64_REGISTER_A2);
	debugState.a3 = IntRegisterValue(LOONGARCH64_REGISTER_A3);
	debugState.a4 = IntRegisterValue(LOONGARCH64_REGISTER_A4);
	debugState.a5 = IntRegisterValue(LOONGARCH64_REGISTER_A5);
	debugState.a6 = IntRegisterValue(LOONGARCH64_REGISTER_A6);
	debugState.a7 = IntRegisterValue(LOONGARCH64_REGISTER_A7);
	debugState.t0 = IntRegisterValue(LOONGARCH64_REGISTER_T0);
	debugState.t1 = IntRegisterValue(LOONGARCH64_REGISTER_T1);
	debugState.t2 = IntRegisterValue(LOONGARCH64_REGISTER_T2);
	debugState.t3 = IntRegisterValue(LOONGARCH64_REGISTER_T3);
	debugState.t4 = IntRegisterValue(LOONGARCH64_REGISTER_T4);
	debugState.t5 = IntRegisterValue(LOONGARCH64_REGISTER_T5);
	debugState.t6 = IntRegisterValue(LOONGARCH64_REGISTER_T6);
	debugState.t7 = IntRegisterValue(LOONGARCH64_REGISTER_T7);
	debugState.t8 = IntRegisterValue(LOONGARCH64_REGISTER_T8);
	debugState.s0 = IntRegisterValue(LOONGARCH64_REGISTER_S0);
	debugState.s1 = IntRegisterValue(LOONGARCH64_REGISTER_S1);
	debugState.s2 = IntRegisterValue(LOONGARCH64_REGISTER_S2);
	debugState.s3 = IntRegisterValue(LOONGARCH64_REGISTER_S3);
	debugState.s4 = IntRegisterValue(LOONGARCH64_REGISTER_S4);
	debugState.s5 = IntRegisterValue(LOONGARCH64_REGISTER_S5);
	debugState.s6 = IntRegisterValue(LOONGARCH64_REGISTER_S6);
	debugState.s7 = IntRegisterValue(LOONGARCH64_REGISTER_S7);
	debugState.s8 = IntRegisterValue(LOONGARCH64_REGISTER_S8);
	debugState.pc = IntRegisterValue(LOONGARCH64_REGISTER_PC);

	// 更新浮点寄存器
	debugState.f0 = FpRegisterValue(LOONGARCH64_REGISTER_F0 - LOONGARCH64_INT_REGISTER_END);
	debugState.f1 = FpRegisterValue(LOONGARCH64_REGISTER_F1 - LOONGARCH64_INT_REGISTER_END);
	debugState.f2 = FpRegisterValue(LOONGARCH64_REGISTER_F2 - LOONGARCH64_INT_REGISTER_END);
	debugState.f3 = FpRegisterValue(LOONGARCH64_REGISTER_F3 - LOONGARCH64_INT_REGISTER_END);
	debugState.f4 = FpRegisterValue(LOONGARCH64_REGISTER_F4 - LOONGARCH64_INT_REGISTER_END);
	debugState.f5 = FpRegisterValue(LOONGARCH64_REGISTER_F5 - LOONGARCH64_INT_REGISTER_END);
	debugState.f6 = FpRegisterValue(LOONGARCH64_REGISTER_F6 - LOONGARCH64_INT_REGISTER_END);
	debugState.f7 = FpRegisterValue(LOONGARCH64_REGISTER_F7 - LOONGARCH64_INT_REGISTER_END);
	debugState.f8 = FpRegisterValue(LOONGARCH64_REGISTER_F8 - LOONGARCH64_INT_REGISTER_END);
	debugState.f9 = FpRegisterValue(LOONGARCH64_REGISTER_F9 - LOONGARCH64_INT_REGISTER_END);
	debugState.f10 = FpRegisterValue(LOONGARCH64_REGISTER_F10 - LOONGARCH64_INT_REGISTER_END);
	debugState.f11 = FpRegisterValue(LOONGARCH64_REGISTER_F11 - LOONGARCH64_INT_REGISTER_END);
	debugState.f12 = FpRegisterValue(LOONGARCH64_REGISTER_F12 - LOONGARCH64_INT_REGISTER_END);
	debugState.f13 = FpRegisterValue(LOONGARCH64_REGISTER_F13 - LOONGARCH64_INT_REGISTER_END);
	debugState.f14 = FpRegisterValue(LOONGARCH64_REGISTER_F14 - LOONGARCH64_INT_REGISTER_END);
	debugState.f15 = FpRegisterValue(LOONGARCH64_REGISTER_F15 - LOONGARCH64_INT_REGISTER_END);
	debugState.f16 = FpRegisterValue(LOONGARCH64_REGISTER_F16 - LOONGARCH64_INT_REGISTER_END);
	debugState.f17 = FpRegisterValue(LOONGARCH64_REGISTER_F17 - LOONGARCH64_INT_REGISTER_END);
	debugState.f18 = FpRegisterValue(LOONGARCH64_REGISTER_F18 - LOONGARCH64_INT_REGISTER_END);
	debugState.f19 = FpRegisterValue(LOONGARCH64_REGISTER_F19 - LOONGARCH64_INT_REGISTER_END);
	debugState.f20 = FpRegisterValue(LOONGARCH64_REGISTER_F20 - LOONGARCH64_INT_REGISTER_END);
	debugState.f21 = FpRegisterValue(LOONGARCH64_REGISTER_F21 - LOONGARCH64_INT_REGISTER_END);
	debugState.f22 = FpRegisterValue(LOONGARCH64_REGISTER_F22 - LOONGARCH64_INT_REGISTER_END);
	debugState.f23 = FpRegisterValue(LOONGARCH64_REGISTER_F23 - LOONGARCH64_INT_REGISTER_END);
	debugState.f24 = FpRegisterValue(LOONGARCH64_REGISTER_F24 - LOONGARCH64_INT_REGISTER_END);
	debugState.f25 = FpRegisterValue(LOONGARCH64_REGISTER_F25 - LOONGARCH64_INT_REGISTER_END);
	debugState.f26 = FpRegisterValue(LOONGARCH64_REGISTER_F26 - LOONGARCH64_INT_REGISTER_END);
	debugState.f27 = FpRegisterValue(LOONGARCH64_REGISTER_F27 - LOONGARCH64_INT_REGISTER_END);
	debugState.f28 = FpRegisterValue(LOONGARCH64_REGISTER_F28 - LOONGARCH64_INT_REGISTER_END);
	debugState.f29 = FpRegisterValue(LOONGARCH64_REGISTER_F29 - LOONGARCH64_INT_REGISTER_END);
	debugState.f30 = FpRegisterValue(LOONGARCH64_REGISTER_F30 - LOONGARCH64_INT_REGISTER_END);
	debugState.f31 = FpRegisterValue(LOONGARCH64_REGISTER_F31 - LOONGARCH64_INT_REGISTER_END);

	return B_OK;
}


target_addr_t
CpuStateLoongArch64::InstructionPointer() const
{
	return IntRegisterValue(LOONGARCH64_REGISTER_PC);
}


void
CpuStateLoongArch64::SetInstructionPointer(target_addr_t address)
{
	SetIntRegister(LOONGARCH64_REGISTER_PC, address);
}


target_addr_t
CpuStateLoongArch64::StackFramePointer() const
{
	return IntRegisterValue(LOONGARCH64_REGISTER_S0);
}


target_addr_t
CpuStateLoongArch64::StackPointer() const
{
	return IntRegisterValue(LOONGARCH64_REGISTER_SP);
}


bool
CpuStateLoongArch64::GetRegisterValue(const Register* reg, BVariant& _value) const
{
	int32 index = reg->Index();
	if (!IsRegisterSet(index))
		return false;

	if (index >= LOONGARCH64_INT_REGISTER_END) {
		// 浮点寄存器
		_value.SetTo(FpRegisterValue(index - LOONGARCH64_INT_REGISTER_END));
	} else {
		// 通用寄存器
		_value.SetTo(IntRegisterValue(index));
	}

	return true;
}


bool
CpuStateLoongArch64::SetRegisterValue(const Register* reg, const BVariant& value)
{
	int32 index = reg->Index();

	if (index >= LOONGARCH64_INT_REGISTER_END) {
		// 浮点寄存器
		if (!value.IsNumber())
			return false;

		SetFpRegister(index - LOONGARCH64_INT_REGISTER_END, value.ToDouble());
	} else {
		// 通用寄存器
		if (!value.IsInteger())
			return false;

		SetIntRegister(index, value.ToUInt64());
	}

	return true;
}


target_addr_t
CpuStateLoongArch64::IntRegisterValue(int32 index) const
{
	if (index < 0 || index >= LOONGARCH64_INT_REGISTER_COUNT)
		return 0;

	return fIntRegisters[index];
}


void
CpuStateLoongArch64::SetIntRegister(int32 index, target_addr_t value)
{
	if (index < 0 || index >= LOONGARCH64_INT_REGISTER_COUNT)
		return;

	fIntRegisters[index] = value;
	fSetRegisters.set(index);
}


double
CpuStateLoongArch64::FpRegisterValue(int32 index) const
{
	if (index < 0 || index >= LOONGARCH64_FP_REGISTER_COUNT)
		return 0.0;

	return fFpRegisters[index];
}


void
CpuStateLoongArch64::SetFpRegister(int32 index, double value)
{
	if (index < 0 || index >= LOONGARCH64_FP_REGISTER_COUNT)
		return;

	fFpRegisters[index] = value;
	fSetRegisters.set(index + LOONGARCH64_INT_REGISTER_END);
}


bool
CpuStateLoongArch64::IsRegisterSet(int32 index) const
{
	if (index < 0 || index >= LOONGARCH64_REGISTER_COUNT)
		return false;

	return fSetRegisters.test(index);
}